﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace ClickNET
{
    public class Config
    {
        public Config()
        {
            // config.xml
            this.m_configFilePath = Path.Combine(Config.ConfigDirectory, Config.DefaultConfigFileName);

            if (!File.Exists(this.m_configFilePath))
                throw new Exception("Unable to find config file: [" + this.m_configFilePath + "]");
            
            this.m_configDoc = new System.Xml.XmlDocument();
            this.m_configDoc.Load(this.m_configFilePath);
        }

        public List<int> GetConfigCommaSeparatedInt(string element, string attribute)
        {
            return this.GetConfigCommaSeparatedInt(element, attribute, string.Empty);
        }

        public List<int> GetConfigCommaSeparatedInt(string element, string attribute, string defaultValue)
        {
            List<int> ints = new List<int>();

            List<string> value = this.GetConfigCommaSeparatedString(element, attribute, defaultValue);

            foreach (String val in value)
            {
                int intVal;
                int.TryParse(val, out intVal);
                ints.Add(intVal);
            }

            return ints;
        }

        public List<string> GetConfigCommaSeparatedString(string element, string attribute)
        {
            return this.GetConfigCommaSeparatedString(element, attribute, string.Empty);
        }

        public List<string> GetConfigCommaSeparatedString(string element, string attribute, string defaultValue)
        {
            char delimiter = ',';
            string value = this.GetConfigString(element, attribute);
            if (String.IsNullOrEmpty(value))
            {
                return ClickNET.Utility.StringConversion.SplitStringIntoList(defaultValue, delimiter);
            }

            return ClickNET.Utility.StringConversion.SplitStringIntoList(value, delimiter);
        }

        /// <summary>
        /// Finds the given element in the config file, then reads the value of the given attribute.
        /// </summary>
        /// <returns>Attribute value, or null</returns>
        public string GetConfigString(string element, string attribute)
        {
            XmlNodeList nodes = this.GetAllConfigElements(element);
            if (null == nodes || 0 == nodes.Count)
                return null;

            return this.TryGetConfigString(nodes[0], attribute);
        }

        private string TryGetConfigString(string element, string attribute)
        {
            XmlNodeList nodes = this.GetAllConfigElements(element);
            if (null == nodes || 0 == nodes.Count)
                return null;

            return this.TryGetConfigString(nodes, attribute);
        }

        private string TryGetConfigString(XmlNodeList nodes, string attribute)
        {
            if (nodes == null)
                return null;

            return this.TryGetConfigString(nodes[0], attribute);
        }

        private string TryGetConfigString(XmlNode node, string attribute)
        {
            if (node == null)
                return null;

            XmlAttributeCollection attributes = node.Attributes;
            if (null == attributes || 0 == attributes.Count)
                return null;

            XmlNode configNode = attributes.GetNamedItem(attribute);
            if (null == configNode)
                return null;

            return configNode.Value;
        }

        private XmlNodeList GetAllConfigElements(string element)
        {
            string selectedNodes = "/config/" + element;
            return this.m_configDoc.SelectNodes(selectedNodes);
        }

        private static readonly Config s_config = new Config();
        public static Config DefaultInstance
        {
            get
            {
                return s_config;
            }
        }

        public static string ConfigDirectory
        {
            get
            {
                return Path.Combine(BaseDirectory, "config");
            }
        }

        public static string DataDirectory
        {
            get
            {
                return Path.Combine(BaseDirectory, "data");
            }
        }

        /// <summary>
        /// The installed path of the site
        /// </summary>
        public static string BaseDirectory
        {
            get
            {
                int indexOfSite = WebDirectory.ToLower().IndexOf(@"www\"); // Assume we'll never rename the 'www' dir
                if (indexOfSite > 0)
                    return WebDirectory.Substring(0, indexOfSite);

                return System.Environment.GetEnvironmentVariable("CLICKNET_HOME");
            }
        }

        /// <summary>
        /// The installed path of the site
        /// </summary>
        public static string WebDirectory
        {
            get
            {
                System.Web.HttpContext hc = System.Web.HttpContext.Current;
                if (null != hc)
                    return hc.Server.MapPath("/");

                return System.Environment.GetEnvironmentVariable("CLICKNET_HOME");
            }
        }

        private const string DefaultConfigFileName = "config.xml";

        private string m_configFilePath;
        private XmlDocument m_configDoc;
    }
}
